/*
 * Copyright Konstantin Triger <kostat@gmail.com> 
 * 
 * This file is part of Jaque - JAva QUEry library <http://code.google.com/p/jaque/>.
 * 
 * Jaque is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Jaque is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package jaque.expressions;

import java.lang.reflect.Method;
import jaque.functions.*;
import jaque.functions.math.*;

/**
 * @author <a href="mailto://object_streaming@googlegroups.com">Konstantin
 *         Triger</a>
 * 
 */
public final class Functions {
	private Functions() {
	}

	/**
	 * Returns the absolute value of an argument evaluation result. In other
	 * words, the result is semantically equivalent to this pseudo-code: <p/>
	 * {@code abs(selector.invoke(T))}
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param selector
	 *            a function to extract the numeric value from T.
	 * @return the absolute value of an argument evaluation result.
	 */
	public static <E extends Number, T> Function<E, T> abs(
			Function<E, ? super T> selector) {
		return new ArithmeticUnaryFunction<E, T>(selector, UnaryOperator.Abs);
	}

	/**
	 * Returns the absolute value of an argument.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @return the absolute value of an argument.
	 */
	public static <T extends Number> Function<T, T> abs() {
		return new ArithmeticUnaryFunction<T, T>(Functions.<T> self(),
				UnaryOperator.Abs);
	}

	/**
	 * Returns the negative value of an argument evaluation result. In other
	 * words, the result is semantically equivalent to this pseudo-code: <p/>
	 * {@code -selector.invoke(T)}
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param selector
	 *            a function to extract the numeric value from T.
	 * @return the negative value of an argument evaluation result.
	 */
	public static <E extends Number, T> Function<E, T> negate(
			Function<E, ? super T> selector) {
		return new ArithmeticUnaryFunction<E, T>(selector, UnaryOperator.Negate);
	}

	/**
	 * Returns the negative value of an argument.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @return the negative value of an argument.
	 */
	public static <T extends Number> Function<T, T> negate() {
		return new ArithmeticUnaryFunction<T, T>(Functions.<T> self(),
				UnaryOperator.Negate);
	}

	/**
	 * Returns the bitwise not value of an argument evaluation result. In other
	 * words, the result is semantically equivalent to this pseudo-code: <p/>
	 * {@code ~selector.invoke(T)}
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param selector
	 *            a function to extract the numeric value from T.
	 * @return the bitwise not value of an argument evaluation result.
	 */
	public static <E extends Number, T> Function<E, T> bitwiseNot(
			Function<E, ? super T> selector) {
		return new ArithmeticUnaryFunction<E, T>(selector, UnaryOperator.Not);
	}

	/**
	 * Returns the bitwise not value of an argument.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @return the bitwise not value of an argument.
	 */
	public static <T extends Number> Function<T, T> not() {
		return new ArithmeticUnaryFunction<T, T>(Functions.<T> self(),
				UnaryOperator.Not);
	}

	/**
	 * Returns the value of {@code left.invoke(T) & right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) & right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> bitwiseAnd(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.And));
	}

	/**
	 * Returns the value of {@code left.invoke(T) + right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) + right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> add(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Add));
	}

	/**
	 * Returns the value of {@code left.invoke(T) - right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) - right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> subtract(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Subtract));
	}

	/**
	 * Returns the value of {@code left.invoke(T) * right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) * right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> multiply(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Multiply));
	}

	/**
	 * Returns the value of {@code left.invoke(T) / right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) / right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> divide(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Divide));
	}

	/**
	 * Returns the value of {@code left.invoke(T) % right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) % right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> modulo(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Modulo));
	}

	/**
	 * Returns the value of {@code left.invoke(T) | right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) | right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> bitwiseOr(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Or));
	}

	/**
	 * Returns the value of <tt>left.invoke(T)<sup>right.invoke(T)</sup></tt>.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of <tt>left.invoke(T)<sup>right.invoke(T)</sup></tt>.
	 */
	public static <E extends Number, T> AggregateFunction<E, T> power(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Power));
	}

	/**
	 * Returns the value of {@code left.invoke(T) << right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) << right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> shiftLeft(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.ShiftLeft));
	}

	/**
	 * Returns the value of {@code left.invoke(T) >>> right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) >>> right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> shiftRight(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.ShiftRight));
	}

	/**
	 * Returns the value of {@code left.invoke(T) ^ right.invoke(T)}.
	 * 
	 * @param <E>
	 *            the type of the numeric type.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) ^ right.invoke(T)}
	 */
	public static <E extends Number, T> AggregateFunction<E, T> xor(
			Function<E, ? super T> left,
			Function<? extends Number, ? super T> right) {
		return cast(new ArithmeticBinaryFunction<E, T>(left, right,
				BinaryOperator.Xor));
	}

	/**
	 * Returns the value of {@code left.invoke(T) && right.invoke(T)}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) && right.invoke(T)}.
	 */
	public static <T> Predicate<T> and(final Function<Boolean, ? super T> left,
			final Function<Boolean, ? super T> right) {
		return new And<T>(left, right);
	}

	/**
	 * Returns the value of {@code left.invoke(T) || right.invoke(T)}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param left
	 *            a function to extract the left hand value from T.
	 * @param right
	 *            a function to extract the right hand value from T.
	 * @return the value of {@code left.invoke(T) || right.invoke(T)}.
	 */
	public static <T> Predicate<T> or(final Function<Boolean, ? super T> left,
			final Function<Boolean, ? super T> right) {
		return new Or<T>(left, right);
	}

	/**
	 * Returns the value of
	 * {@code left.invoke(T).compareTo(right.invoke(T)) < 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @return the value of
	 *         {@code left.invoke(T).compareTo(right.invoke(T)) < 0}.
	 */
	public static <T, Key extends Comparable<? super Key>> Comparator<T, Key> lessThan(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right) {
		return Functions.<T, Key> lessThan(left, right, Comparator
				.<Key> getComparableDefault());
	}

	/**
	 * Returns the value of
	 * {@code comparator.compare(left.invoke(T), right.invoke(T)) < 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @param comparator
	 *            comparator of Keys
	 * @return the value of
	 *         {@code comparator.compare(left.invoke(T), right.invoke(T)) < 0}.
	 */
	public static <T, Key> Comparator<T, Key> lessThan(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right,
			final java.util.Comparator<? super Key> comparator) {
		return new Comparator<T, Key>(left, right,
				Comparator.Operator.LessThan, comparator);
	}

	// public static <Key extends Comparable<? super Key>> Predicate2<Key>
	// lessThanOrEqual(
	// Function<Key, Key> right) {
	// return lessThanOrEqual(Expression.<Key> self(), right);
	// }

	/**
	 * Returns the value of
	 * {@code left.invoke(T).compareTo(right.invoke(T)) <= 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @return the value of
	 *         {@code left.invoke(T).compareTo(right.invoke(T)) <= 0}.
	 */
	public static <T, Key extends Comparable<? super Key>> Comparator<T, Key> lessThanOrEqual(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right) {
		return Functions.<T, Key> lessThanOrEqual(left, right, Comparator
				.<Key> getComparableDefault());
	}

	/**
	 * Returns the value of
	 * {@code comparator.compare(left.invoke(T), right.invoke(T)) <= 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @param comparator
	 *            comparator of Keys
	 * @return the value of
	 *         {@code comparator.compare(left.invoke(T), right.invoke(T)) <= 0}.
	 */
	public static <T, Key> Comparator<T, Key> lessThanOrEqual(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right,
			final java.util.Comparator<? super Key> comparator) {
		return new Comparator<T, Key>(left, right,
				Comparator.Operator.LessThanOrEqual, comparator);
	}

	/**
	 * Returns the value of
	 * {@code left.invoke(T).compareTo(right.invoke(T)) == 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @return the value of
	 *         {@code left.invoke(T).compareTo(right.invoke(T)) == 0}.
	 */
	public static <T, Key extends Comparable<? super Key>> Comparator<T, Key> equal(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right) {
		return Functions.<T, Key> equal(left, right, Comparator
				.<Key> getComparableDefault());
	}

	/**
	 * Returns the value of
	 * {@code comparator.compare(left.invoke(T), right.invoke(T)) == 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @param comparator
	 *            comparator of Keys
	 * @return the value of
	 *         {@code comparator.compare(left.invoke(T), right.invoke(T)) == 0}.
	 */
	public static <T, Key> Comparator<T, Key> equal(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right,
			final java.util.Comparator<? super Key> comparator) {
		return new Comparator<T, Key>(left, right, Comparator.Operator.Equal,
				comparator);
	}

	// public static <Key extends Comparable<? super Key>> Predicate2<Key>
	// greaterThanOrEqual(
	// Function<? super Key, ? extends Key> right) {
	// return greaterThanOrEqual(Expression.<Key> self(), right);
	// }

	/**
	 * Returns the value of
	 * {@code left.invoke(T).compareTo(right.invoke(T)) >= 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @return the value of
	 *         {@code left.invoke(T).compareTo(right.invoke(T)) >= 0}.
	 */
	public static <T, Key extends Comparable<? super Key>> Comparator<T, Key> greaterThanOrEqual(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right) {
		return Functions.<T, Key> greaterThanOrEqual(left, right, Comparator
				.<Key> getComparableDefault());
	}

	/**
	 * Returns the value of
	 * {@code comparator.compare(left.invoke(T), right.invoke(T)) >= 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @param comparator
	 *            comparator of Keys
	 * @return the value of
	 *         {@code comparator.compare(left.invoke(T), right.invoke(T)) >= 0}.
	 */
	public static <T, Key> Comparator<T, Key> greaterThanOrEqual(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right,
			final java.util.Comparator<? super Key> comparator) {
		return new Comparator<T, Key>(left, right,
				Comparator.Operator.GreaterThanOrEqual, comparator);
	}

	/**
	 * Returns the value of
	 * {@code left.invoke(T).compareTo(right.invoke(T)) > 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @return the value of
	 *         {@code left.invoke(T).compareTo(right.invoke(T)) > 0}.
	 */
	public static <T, Key extends Comparable<? super Key>> Comparator<T, Key> greaterThan(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right) {
		return Functions.<T, Key> greaterThan(left, right, Comparator
				.<Key> getComparableDefault());
	}

	/**
	 * Returns the value of
	 * {@code comparator.compare(left.invoke(T), right.invoke(T)) > 0}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param <Key>
	 *            the type of key to compare.
	 * @param left
	 *            a function to extract the left hand Key from T.
	 * @param right
	 *            a function to extract the right hand Key from T.
	 * @param comparator
	 *            comparator of Keys
	 * @return the value of
	 *         {@code comparator.compare(left.invoke(T), right.invoke(T)) > 0}.
	 */
	public static <T, Key> Comparator<T, Key> greaterThan(
			Function<? extends Key, ? super T> left,
			Function<? extends Key, ? super T> right,
			final java.util.Comparator<? super Key> comparator) {
		return new Comparator<T, Key>(left, right,
				Comparator.Operator.GreaterThan, comparator);
	}

	/**
	 * Represents a function returning a constant value.
	 * 
	 * @param <Result>
	 *            the type of returned value.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param result
	 *            value to return.
	 * @return result.
	 */
	public static <Result, T> Function<Result, T> constant(final Result result) {
		return new ConstantSelector<Result, T>(result);
	}

	// public static <T> Function<T, T> constant(final T result) {
	// return new ConstantSelector<T, T>(result);
	// }

	/**
	 * Represents a function returning passed argument.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence and type of returned
	 *            value.
	 * @return passed argument.
	 */
	@SuppressWarnings("unchecked")
	public static <T> Function<T, T> self() {
		return (Function<T, T>) SelfSelector;
	}

	//
	// @SuppressWarnings("unchecked")
	// public static <T> Function<T, T> self(final Class<T> type) {
	// return (Function<T, T>) SelfSelector;
	// }

	/**
	 * Represents a function returning value of a property using reflection.
	 * 
	 * @param <Result>
	 *            the type of returned value.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param outerType
	 *            Class of the objects in the sequence.
	 * @param propertyName
	 *            name of the property to retrieve. The implementation will look
	 *            for get&lt;propertyName&gt;() method.
	 * @return value of the property.
	 * @throws NoSuchMethodException
	 */
	public static <Result, T> Function<Result, T> property(
			Class<? super T> outerType, // Class<? super Result> resultType,
			String propertyName) throws NoSuchMethodException {
		return new Property<Result, T>(outerType, propertyName);
	}

	/**
	 * Represents a function returning value of a field using reflection.
	 * 
	 * @param <Result>
	 *            the type of returned value.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param outerType
	 *            Class of the objects in the sequence.
	 * @param fieldName
	 *            name of the field to retrieve.
	 * @return value of the field.
	 * @throws NoSuchFieldException
	 */
	public static <Result, T> Function<Result, T> field(
			Class<? super T> outerType, // Class<? super Result> resultType,
			String fieldName) throws NoSuchFieldException {
		return new Field<Result, T>(outerType, fieldName);
	}

	private static <R, Result extends R, T> AggregateFunction<Result, T> cast(
			AggregateFunction<R, T> value) {
		return new Cast<T, R, Result>(value);
	}

	/**
	 * Returns the value of {@code first.invoke(T) ?? second.invoke(T)}.
	 * <p/>Note, that either ifTrue or ifFalse function is evaluated.
	 * 
	 * @param <Result>
	 *            the type of returned value.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param first
	 *            a function to evaluate if predicate returns true.
	 * @param second
	 *            a function to evaluate if predicate returns false.
	 * @return the value of {@code first.invoke(T) ?? second.invoke(T)}.
	 */
	public static <Result, T> Function<Result, T> coalesce(
			final Function<? extends Result, ? super T> first,
			final Function<? extends Result, ? super T> second) {
		return new Function<Result, T>() {
			// @Override
			public Result invoke(T t) throws Throwable {
				Result r = first.invoke(t);
				return r != null ? r : second.invoke(t);
			}
		};
	}

	/**
	 * Returns the value of {@code operand.invoke(T) instanceof type}.
	 * 
	 * @param <Result>
	 *            the type of returned value.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param operand
	 *            a function to extract the operand from T
	 * @param type
	 *            the Class to test by.
	 * @return the value of {@code operand.invoke(T) instanceof type}.
	 */
	public static <Result, T> Predicate<T> instanceOf(
			final Function<? extends Result, ? super T> operand,
			final Class<?> type) {
		return new Predicate<T>() {
			// @Override
			public Boolean invoke(T t) throws Throwable {
				return type.isInstance(operand.invoke(t));
			}
		};
	}

	/**
	 * Returns the value of
	 * {@code predicate.invoke(first, second) ? first : second}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param predicate
	 *            predicate to test.
	 * @return the value of
	 *         {@code predicate.invoke(first, second) ? first : second}.
	 */
	public static <T> Function2<T, T, T> conditional(
			final Function2<Boolean, T, T> predicate) {
		return new Function2<T, T, T>() {

			// @Override
			public T invoke(T t, T r) throws Throwable {
				if (t == null)
					return r;
				return predicate.invoke(t, r) ? t : r;
			}

		};
	}

	/**
	 * Returns the value of
	 * {@code predicate.invoke(T) ? ifTrue.invoke(T) : ifFalse.invoke(T)}.
	 * <p/>Note, that either ifTrue or ifFalse function is evaluated.
	 * 
	 * @param <Result>
	 *            the type of returned value.
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param predicate
	 *            predicate to test.
	 * @param ifTrue
	 *            a function to evaluate if predicate returns true.
	 * @param ifFalse
	 *            a function to evaluate if predicate returns false.
	 * @return the value of
	 *         {@code predicate.invoke(T) ? ifTrue.invoke(T) : ifFalse.invoke(T)}.
	 */
	public static <Result, T> Function<Result, T> iif(
			final Function<Boolean, ? super T> predicate,
			final Function<? extends Result, ? super T> ifTrue,
			final Function<? extends Result, ? super T> ifFalse) {
		return new Function<Result, T>() {
			// @Override
			public Result invoke(T t) throws Throwable {
				if (predicate.invoke(t))
					return ifTrue.invoke(t);

				return ifFalse.invoke(t);
			}
		};
	}

	/**
	 * Negates the return value of a predicate. In other words:
	 * {@code !predicate.invoke(T)}.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param predicate
	 *            predicate to negate its evaluation result.
	 * @return value of {@code !predicate.invoke(T)}.
	 */
	public static <T> Predicate<T> not(Function<Boolean, T> predicate) {
		return new Not<T>(predicate);
	}

	/**
	 * Counts invocations and returns true while the counter is less than
	 * specified.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param value
	 *            breaking number of invocations.
	 * @return true while the counter is less than specified, otherwise false.
	 */
	public static <T> Predicate<T> indexLessThan(final int value) {
		if (value < 0)
			throw new IndexOutOfBoundsException("value");
		return new CountingPredicate<T>() {
			@Override
			public Boolean invoke(T t, int index) throws Throwable {
				return index < value;
			}
		};
	}

	/**
	 * Counts invocations and returns true while the counter is less or equal
	 * than specified.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param value
	 *            breaking number of invocations.
	 * @return true while the counter is less or equal than specified, otherwise
	 *         false.
	 */
	public static <T> Predicate<T> indexLessThanOrEqual(final int value) {
		if (value < 0)
			throw new IndexOutOfBoundsException("value");
		return new CountingPredicate<T>() {
			@Override
			public Boolean invoke(T t, int index) throws Throwable {
				return index <= value;
			}
		};
	}

	/**
	 * Counts invocations and returns true while the counter is greater than
	 * specified.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param value
	 *            breaking number of invocations.
	 * @return true while the counter is greater than specified, otherwise
	 *         false.
	 */
	public static <T> Predicate<T> indexGreaterThan(final int value) {
		if (value < 0)
			throw new IndexOutOfBoundsException("value");
		return new CountingPredicate<T>() {
			@Override
			public Boolean invoke(T t, int index) throws Throwable {
				return index > value;
			}
		};
	}

	/**
	 * Counts invocations and returns true while the counter is greater or equal
	 * than specified.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param value
	 *            breaking number of invocations.
	 * @return true while the counter is greater or equal than specified,
	 *         otherwise false.
	 */
	public static <T> Predicate<T> indexGreaterThanOrEqual(final int value) {
		if (value < 0)
			throw new IndexOutOfBoundsException("value");
		return new CountingPredicate<T>() {
			@Override
			public Boolean invoke(T t, int index) throws Throwable {
				return index >= value;
			}
		};
	}

	/**
	 * Counts invocations and returns true while the counter is inside the
	 * specified range.
	 * 
	 * @param <T>
	 *            the type of the objects in the sequence.
	 * @param start
	 *            lower limit of invocations.
	 * @param count
	 *            number of invocations to break.
	 * @return true while the counter is inside the specified range.
	 */
	public static <T> Predicate<T> indexRange(final int start, final int count) {
		if (start < 0)
			throw new IndexOutOfBoundsException("start");
		return and(indexGreaterThanOrEqual(start), indexLessThan(start + count));
	}

	private static abstract class LogicalUnaryOperation<T> extends
			UnaryFunction<Boolean, T> implements Predicate<T> {
		protected LogicalUnaryOperation(Function<Boolean, ? super T> left) {
			super(left);
		}
	}

	private static final class Not<T> extends LogicalUnaryOperation<T> {
		protected Not(Function<Boolean, ? super T> left) {
			super(left);
		}

		@Override
		public Boolean invoke(T source) throws Throwable {
			return !super.invoke(source);
		}
	}

	private static final class Cast<T, R, Result extends R> implements
			AggregateFunction<Result, T> {
		private final AggregateFunction<R, T> _value;

		public Cast(AggregateFunction<R, T> value) {
			_value = value;
		}

		@SuppressWarnings("unchecked")
		// @Override
		public Result invoke(T t) throws Throwable {
			return (Result) _value.invoke(t);
		}

		@SuppressWarnings("unchecked")
		// @Override
		public Result invoke(Result t, T r) throws Throwable {
			return (Result) _value.invoke(t, r);
		}
	}

	private static final class ConstantSelector<Result, T> implements
			Function<Result, T> {
		private final Result _value;

		public ConstantSelector(Result value) {
			_value = value;
		}

		// @Override
		public Result invoke(T t) throws Throwable {
			return _value;
		}
	}

	private static final Function<Object, Object> SelfSelector = new Function<Object, Object>() {

		// @Override
		public Object invoke(Object t) throws Throwable {
			return t;
		}
	};

	private static final class Property<Result, T> implements
			Function<Result, T> {

		private final Method _method;

		// private final String _propertyName;

		public Property(Class<? super T> type, String propertyName)
				throws NoSuchMethodException {

			if (type == null)
				throw new NullPointerException("type");
			if (propertyName == null)
				throw new NullPointerException("propetyName");

			// _propertyName = propertyName;
			_method = type.getDeclaredMethod("get" + propertyName);
		}

		@SuppressWarnings("unchecked")
		// @Override
		public Result invoke(T t) throws Throwable {
			return (Result) _method.invoke(t);
		}
	}

	private static final class Field<Result, T> implements Function<Result, T> {
		private final java.lang.reflect.Field _field;

		// private final String _fieldName;

		public Field(Class<? super T> type, String fieldName)
				throws NoSuchFieldException {

			if (type == null)
				throw new NullPointerException("type");
			if (fieldName == null)
				throw new NullPointerException("fieldName");

			// _fieldName = fieldName;
			_field = type.getDeclaredField(fieldName);
		}

		@SuppressWarnings("unchecked")
		// @Override
		public Result invoke(T t) throws Throwable {
			return (Result) _field.get(t);
		}
	}

	private static abstract class LogicalBinaryOperation<T> extends
			BinaryFunction<Boolean, T> implements Predicate<T> {
		protected LogicalBinaryOperation(Function<Boolean, ? super T> first,
				Function<Boolean, ? super T> second) {
			super(first, second);
		}
	}

	private static final class And<T> extends LogicalBinaryOperation<T> {
		public And(Function<Boolean, ? super T> first, Function<Boolean, ? super T> second) {
			super(first, second);
		}

		// @Override
		public Boolean invoke(Boolean t, T source) throws Throwable {
			return t && getSecond().invoke(source);
		}
	}

	private static final class Or<T> extends LogicalBinaryOperation<T> {
		public Or(Function<Boolean, ? super T> first, Function<Boolean, ? super T> second) {
			super(first, second);
		}

		// @Override
		public Boolean invoke(Boolean t, T source) throws Throwable {
			return t || getSecond().invoke(source);
		}
	}

	private static final class ArithmeticUnaryFunction<Result extends Number, T>
			extends UnaryFunction<Result, T> {

		private final UnaryOperator _op;

		public ArithmeticUnaryFunction(
				Function<? extends Result, ? super T> left, UnaryOperator op) {
			super(left);
			_op = op;
		}

		@SuppressWarnings("unchecked")
		@Override
		public Result invoke(T source) throws Throwable {
			return (Result) _op.eval(super.invoke(source));
		}
	}

	private static final class ArithmeticBinaryFunction<E extends Number, T>
			extends BinaryFunction<Number, T> {

		private final BinaryOperator _op;

		public ArithmeticBinaryFunction(Function<E, ? super T> first,
				Function<? extends Number, ? super T> second, BinaryOperator op) {
			super(first, second);
			_op = op;
		}

		// @Override
		@SuppressWarnings("unchecked")
		public E invoke(Number l, T source) throws Throwable {
			Number r = getSecond().invoke(source);

			return (E) _op.eval(l, r);
		}
	}
}
